﻿using System;
using System.Collections;
using System.Text;
using System.Threading;

using GameServer.Managers;
using GameServer.Networking;
using GameServer.Networking.Packets;
using GameServer.Virtual_Objects.User;

namespace GameServer.Virtual_Objects.Room
{
    struct floorItem
    {
        public int ID;
        public int Owner;
        public float[] Position;
        public string Obj;

        public floorItem(int iID, int iSlotOwner, float[] fPosition, string Object)
        {
            this.ID = iID;
            this.Owner = iSlotOwner;
            this.Position = fPosition;
            this.Obj = Object.ToUpper();
        }
    }

    class virtualRoom
    {
        public int ID;
        public int Channel = 1;
        public String Name = "Default-Room";
        public int EnablePassword = 0;
        public String Password = "NULL";
        public bool SuperMaster = false;
        public int MapID = 0;
        public int Kills = 2;
        public int PremiumOnly = 0;
        public int VoteKick = 0;
        public int RoomStatus = 1; // 1 Waiting - 0 & 2 Playing
        public int Mode = 0; // Mode : 0 = Explosive, 1 = FFA, 2 = Deathmatch, 3 = Conquest
        public int RoomType = 0;
        public int LevelLimit = 0;
        public int Ping = 0;
        public int Rounds = 3; // 0 = 1, 1 = 3, 2 = 5, 3 = 7, 4 = 9
        public int VehicleRespawnCount = 0;
        public bool FirstBlood = false;
        public bool UserLimit = false;
        public int UserLimitCount = 0;
        public bool VehiclesChecked = false;
        public int cNIUExplosivePoints = 0;
        public int cDerbExplosivePoints = 0;
        public bool Sleep = false;
        public int FFAKillPoints = 10;
        public virtualUser[] oPlayers = new virtualUser[0];
        public ArrayList NIUPlayers = new ArrayList();
        public ArrayList DeberanPlayers = new ArrayList();

        public ArrayList FloorItems = new ArrayList();
        public ArrayList Cars = new ArrayList();
        public int PXItemID = 0;

        public int RoundTimeLeft = 180000;
        public int RoundTimeSpent = 0;
        public int[] Flags = new int[32];

        private Hashtable Users = new Hashtable();
        public ArrayList Zombies = new ArrayList();
        private int RoomMaster = 0;
        private int MaxUsers = 0;

        #region In-Game

        public bool GameActive = false;
        public bool EndGameFreeze = false;

        public int LastTick = 0;

        public DateTime RoundEnd = DateTime.Now;
        public bool bombPlanted = false;
        public bool bombDefused = false;
        public int explosiveRounds = 0;
        public int dmRounds = 0;

        public int highestKills = 0;
        public int SpawnLocation = -1;

        public int KillsNIULeft = 10;
        public int KillsDeberanLeft = 10;
        public int TimeLimit = 4;
        public int VoteKickTime = 0;
        public int KickSeat = -1;
        public int KickYes = 0;
        public int KickNo = 0;
        public int RespawnVehicleCount = 120;
        public bool KickAlready = false;
        public string[] KickString = new string[1];

        public int spawnedPlayers = 0;
        public bool readyZombie = false;
        public bool beginSpawn = false;

        public ArrayList Spectators = new ArrayList();

        public int debug = 0;

        #endregion

        public virtualRoom() { }

        ~virtualRoom()
        {
            GC.Collect();
        }

        public int MaxPlayers
        {
            get { return MaxUsers; }
            set { MaxUsers = value; }
        }

        public ArrayList Players
        {
            get
            {
                return new ArrayList(Users.Values);
            }
        }

        public virtualUser getSpectatorByID(int SpectatorID)
        {
            foreach (virtualUser SpectatorUser in Spectators)
            {
                if (SpectatorUser.SpectatorID == SpectatorID)
                    return SpectatorUser;
            }
            return null;
        }

        public int getMaxIDSpectator
        {
            get
            {
                int SpectatorID = 1;
                foreach (virtualUser SpectatorUser in Spectators)
                {
                    if (SpectatorUser.SpectatorID > SpectatorID)
                        SpectatorID = SpectatorUser.SpectatorID;
                }
                return SpectatorID;
            }
        }

        public int getIDSpectator(virtualUser User)
        {
            for (int I = 0; I < Spectators.Count; I++)
            {
                if (getSpectatorByID(I) == User)
                    return I;
            }
            int Count = getMaxIDSpectator + 1;
            if (Count > 10) Count -= 10;
            return Count;
        }

        public bool addSpectator(virtualUser User)
        {
            if (Spectators.Count >= 10) return false;
            if (Spectators.Contains(User) == false && User != null)
            {
                User.isSpectating = true;
                User.Room = this;
                User.RoomSlot = 32 + Spectators.Count + getIDSpectator(User);
                foreach (virtualUser RoomUser in Spectators)
                    if (User.RoomSlot == RoomUser.RoomSlot)
                        User.RoomSlot += 1;
                User.SpectatorID = getIDSpectator(User);
                Spectators.Add(User);
                return true;
            }
            return false;
        }

        public void removeSpectator(virtualUser User)
        {
            if (Spectators.Contains(User))
            {
                send(new PACKET_ROOM_UDP_SPECTATE(User, this));
                User.send(new PACKET_SPECTATE_ROOM());
                User.send(new PACKET_ROOM_LIST(User, 0));
                User.Room = null;
                User.RoomSlot = 0;
                User.SpectatorID = -1;
                User.isSpectating = false;
                //User.disconnect();
                Spectators.Remove(User);
            }
        }

        public int getPlayers()
        {
            ArrayList PlayerList = new ArrayList();
            int ValuePlayers = 0;
            for (int i = 0; i < MaxPlayers; i++)
            {
                if (oPlayers.GetValue(i) is virtualUser)
                {
                    ValuePlayers++;
                }
            }
            return ValuePlayers;
        }

        public int PlayerCount { get { return Users.Count; } }
        public int RoomMasterSlot { get { return RoomMaster; } }

        public void send(Packet p)
        {
            foreach (virtualUser RoomUser in ((Hashtable)Users.Clone()).Values)
            {
                RoomUser.send(p);
            }
            foreach (virtualUser SpectatorUser in Spectators)
            {
                SpectatorUser.send(p);
            }
        }

        public ArrayList getTeamPlayer(int Team)
        {
            ArrayList ar = new ArrayList();
            foreach (User.virtualUser c in Players)
            {
                if (getSide(c) == Team)
                {
                    ar.Add(c);
                }
            }
            return ar;
        }

        public bool isJoinAble()
        {
            if (Channel == 4 && RoomStatus != 1)
                return false;

            if (Players.Count == MaxPlayers || UserLimit && Players.Count >= UserLimitCount)
                // Room is Full
                return false;

            if (RoomStatus != 1 && Mode == 2 && (KillsNIULeft <= 30 || KillsDeberanLeft <= 30))
            { // Less then 30 Kills Left
                return false;
            }

            if (RoomStatus != 1 && Mode == 0 && ((10 + (5 * Rounds)) - highestKills) <= 10)
            { // Less then 10 Kills Left - FFA
                return false;
            }
            return true;
        }

        protected Vehicle[] _Vehicles;
        public Vehicle[] Vehicles
        {
            get { return this._Vehicles; }
            set { this._Vehicles = value; }
        }

        public int getVehiclesCount()
        {
            int Count = Vehicles.Length;
            if (MapID == 50) Count += 1;
            return Count;
        }

        public ArrayList getVehicles()
        {
            return new ArrayList(((Hashtable)_Vehicles.Clone()).Values);
        }
        public int VehicleIndexOf(Vehicle V)
        {
            for (int i = 0; i <= this._Vehicles.Length - 1; i++)
            {
                if (object.ReferenceEquals(this._Vehicles[i], V))
                    return i;
            }
            return -1;
        }

        public bool isPremMap()
        {
            try
            {
                switch (MapID)
                {
                    case 10: return true;
                    case 20: return true;
                    case 21: return true;
                    case 26: return true;
                    case 15: return true;
                    case 17: return true;
                    case 19: return true;
                    case 23: return true;
                    case 33: return true;
                    case 37: return true;
                    case 39: return true;
                    case 9: return true;
                    case 11: return true;
                    case 16: return true;
                    case 24: return true;
                    case 25: return true;
                    case 30: return true;
                    case 31: return true;
                    case 34: return true;
                    case 36: return true;
                    case 38: return true;
                    default: return false;
                }
            }
            catch
            {
                return false;
            }
        }


        public void newRound(int WinningTeam)
        {
            try
            {
                ArrayList tempPlayers = Players;
                foreach (virtualUser Spectator in Spectators)
                    tempPlayers.Add(Spectator);

                if (WinningTeam == 0 && cDerbRounds + 1 == explosiveRounds || WinningTeam == 1 && cNiuRounds + 1 == explosiveRounds)
                {
                    endGame();
                    return;
                }
                foreach (virtualUser Client in tempPlayers)
                {
                    //Client.send(new PACKET_CLIENT_PACKET(666));
                    Client.send(new RoomDataNewRound(Client, this, WinningTeam, true));
                }
                Sleep = true;
                Thread.Sleep(4500);
                foreach (virtualUser Client in tempPlayers)
                {
                    if (bombPlanted == true)
                    {
                        WinningTeam = 0;
                    }
                    else if (bombDefused == true)
                    {
                        WinningTeam = 1;
                    }

                    Client.isSpawned = false;
                    Client.send(new RoomDataNewRound(Client, this, WinningTeam, false));
                    Client.Health = 1000;
                    RoundTimeLeft = 180000;
                    RoundTimeSpent = 0;
                }
                Sleep = false;
                bombDefused = false;
                bombPlanted = false;
            }
            catch { }
        }

        private void RespawnVehicles()
        {
            for (int I = 0; I < Vehicles.Length; I++)
            {
                if (Vehicles[I].Health <= 0)
                {
                    send(new PACKET_VEHICLE_RESPAWN(I));
                    Vehicles[I].Health = Vehicles[I].MaxHealth;
                    //Todo: Reset ammo
                }
            }
        }

        private void ResetZombieRoomStart()
        {
            spawnedPlayers = 0;
            spawnedZombies = 0;
            ZombieSeats = 4;
            Wave = 0;
            spawnedMadmans = 0;
            spawnedManiacs = 0;
            spawnedGrinders = 0;
            spawnedGrounders = 0;
            spawnedHeavys = 0;
            spawnedGrowlers = 0;
            spawnedLovers = 0;
            spawnedHandgemans = 0;
            spawnedChariots = 0;
            spawnedCrushers = 0;
            toWave = 0;
            zombieKills = 0;
            Zombies.Clear();
            zombiePoints = 0;
            prepareReady = false;
            readyZombie = false;
            waveTime = 15;
        }

        public bool Start()
        {
            try
            {
                foreach (virtualUser RoomUser in Players)
                {
                    if (RoomUser.isReady == false && RoomUser.RoomSlot != RoomMasterSlot)
                    {
                        send(new PACKET_CHAT("SYSTEM", PACKET_CHAT.ChatType.Whisper, "SYSTEM >> All players must be ready before start the game!!", RoomUser.SessionID, RoomUser.Nickname));
                        return false;
                    }
                    /*else if (MapID == 33)
                    {
                        send(new PACKET_CHAT("SYSTEM", PACKET_CHAT.ChatType.Whisper, "SYSTEM >> Beringia it's closed due to a bug, sorry guys :/!!", RoomUser.SessionID, RoomUser.Nickname));
                        return false;
                    }*/
                    if (Config.Debug == 0)
                    {
                        if (Channel != 4 && PlayerCount <= 1)
                            return false;
                    }
                }

                // Reset Room //
                SpawnLocation = 0;
                GameActive = false;
                EndGameFreeze = false;
                FirstBlood = false;
                Sleep = false;
                highestKills = cNiuRounds = cDerbRounds = KillsNIULeft = KillsDeberanLeft = VehicleRespawnCount = 0;
                bombPlanted = false;
                bombDefused = false;
                RoundTimeSpent = 0;
                FloorItems.Clear();
                Cars.Clear();
                ResetZombieRoomStart();
                //
                if (Mode == 0)
                {
                    switch (Rounds)
                    {
                        case 0: explosiveRounds = 1; break;
                        case 1: explosiveRounds = 3; break;
                        case 2: explosiveRounds = 5; break;
                        case 3: explosiveRounds = 7; break;
                        case 4: explosiveRounds = 9; break;
                    }
                }
                else if (Mode == 1)
                {
                    FFAKillPoints = 10 + (5 * Rounds);
                }
                else if (Mode == 2)
                {
                    switch (Rounds)
                    {
                        case 0: KillsDeberanLeft = KillsNIULeft = 30; break;
                        case 1: KillsDeberanLeft = KillsNIULeft = 50; break;
                        case 2: KillsDeberanLeft = KillsNIULeft = 100; break;
                        case 3: KillsDeberanLeft = KillsNIULeft = 150; break;
                        case 4: KillsDeberanLeft = KillsNIULeft = 200; break;
                    }
                }
                else if (Mode == 3)
                {
                    switch (Rounds)
                    {
                        case 0: KillsDeberanLeft = KillsNIULeft = 30; break;
                        case 1: KillsDeberanLeft = KillsNIULeft = 50; break;
                        case 2: KillsDeberanLeft = KillsNIULeft = 100; break;
                        case 3: KillsDeberanLeft = KillsNIULeft = 150; break;
                        case 4: KillsDeberanLeft = KillsNIULeft = 200; break;
                        case 5: KillsDeberanLeft = KillsNIULeft = 300; break;
                    }
                }
                for (int I = 0; I < 32; I++)
                {
                    Flags[I] = -1;
                }
                if (MapID == 49 || Channel == 2 || Channel == 3 || Channel == 4)
                {
                    this._Vehicles = MapVehicles.GetVehicles(this.MapID);
                    VehiclesChecked = true;
                }
                if (Mode != 0)
                {
                    switch (TimeLimit)
                    {
                        case 1:
                            RoundTimeLeft = 599000;
                            break;
                        case 2:
                            RoundTimeLeft = 1199000;
                            break;
                        case 3:
                            RoundTimeLeft = 1799000;
                            break;
                        case 4:
                            RoundTimeLeft = 2399000;
                            break;
                        case 5:
                            RoundTimeLeft = 2399000;
                            break;
                        case 6:
                            RoundTimeLeft = -1000;
                            break;
                    }
                }
                else
                {
                    RoundTimeLeft = 180000; // Round Timer
                }
                if (Channel == 4)
                    loadZombieObjects();

                foreach (virtualUser RoomUser in Players)
                {
                    ResetRoomStats(RoomUser);
                }
                return true;
            }
            catch (Exception ex)
            {
                Log.WriteError("Couldn't start room " + ID + ", error: " + ex.Message);
                return false;
            }
        }

        public int addPXItem(int Owner, float[] Position, string Obj)
        {
            int ID = PXItemID++;
            FloorItems.Add(new floorItem(ID, Owner, Position, Obj));
            return ID;
        }

        public floorItem removePXItem(int ID)
        {
            foreach (floorItem Item in FloorItems)
            {
                if (Item.ID == ID)
                {
                    FloorItems.Remove(Item);
                    return Item;
                }
            }

            return new floorItem(-1, -1, null, "");
        }

        public ArrayList removePXItems(int Owner)
        {
            ArrayList Items = new ArrayList();

            foreach (floorItem Item in FloorItems)
            {
                if (Item.Owner == Owner)
                {
                    Items.Add(Item);
                    removePXItem(Item.ID);
                }
            }

            return Items;
        }

        #region Zombie

        public bool ZombiesFreeze = false;
        public int Wave = 0;
        public int ZombieSeats = 4;
        public int ZombieWave = 0;

        int spawnedMadmans = 0;
        int spawnedManiacs = 0;
        int spawnedGrinders = 0;
        int spawnedGrounders = 0;
        int spawnedHeavys = 0;
        int spawnedGrowlers = 0;
        int spawnedLovers = 0;
        int spawnedHandgemans = 0;
        int spawnedChariots = 0;
        int spawnedCrushers = 0;

        public void spawnMadman(int howMuch)
        {
            try
            {
                virtualZombie _Zombie = new virtualZombie();
                send(new PACKET_SPAWN_ZOMBIE_MADMAN(this, ZombieSeats));
                _Zombie.ID = ZombieSeats;
                _Zombie.Health = 1;
                _Zombie.Points = 1;
                _Zombie.doDamage = 150;
                Zombies.Add(_Zombie);
                ZombieSeats++;
                spawnedMadmans++;
                spawnedZombies++;
            }
            catch { }
        }

        public void spawnManiac(int howMuch)
        {
            try
            {
                virtualZombie _Zombie = new virtualZombie();
                send(new PACKET_SPAWN_ZOMBIE_MANIAC(this, ZombieSeats));
                _Zombie.ID = ZombieSeats;
                _Zombie.Health = 2;
                _Zombie.Points = 1;
                _Zombie.doDamage = 150;
                Zombies.Add(_Zombie);
                ZombieSeats++;
                spawnedManiacs++;
                spawnedZombies++;
            }
            catch { }
        }

        public void spawnGrinder(int howMuch)
        {
            try
            {
                virtualZombie _Zombie = new virtualZombie();
                send(new PACKET_SPAWN_ZOMBIE_GRINDER(this, ZombieSeats));
                _Zombie.ID = ZombieSeats;
                _Zombie.Health = 100;
                _Zombie.Points = 2;
                _Zombie.doDamage = 200;
                Zombies.Add(_Zombie);
                ZombieSeats++;
                spawnedGrinders++;
                spawnedZombies++;
            }
            catch { }
        }

        public void spawnGrounder(int howMuch)
        {
            try
            {
                virtualZombie _Zombie = new virtualZombie();
                send(new PACKET_SPAWN_ZOMBIE_GROUNDER(this, ZombieSeats));
                _Zombie.ID = ZombieSeats;
                _Zombie.Health = 111;
                _Zombie.Points = 2;
                _Zombie.doDamage = 200;
                Zombies.Add(_Zombie);
                ZombieSeats++;
                spawnedGrounders++;
                spawnedZombies++;
            }
            catch { }
        }

        public void spawnHeavy(int howMuch)
        {
            try
            {
                virtualZombie _Zombie = new virtualZombie();
                send(new PACKET_SPAWN_ZOMBIE_HEAVY(this, ZombieSeats));
                _Zombie.ID = ZombieSeats;
                _Zombie.Health = 9000;
                _Zombie.Points = 10;
                _Zombie.doDamage = 1250;
                Zombies.Add(_Zombie);
                ZombieSeats++;
                spawnedHeavys++;
                spawnedZombies++;
            }
            catch { }
        }

        public void spawnGrowler(int howMuch)
        {
            try
            {
                virtualZombie _Zombie = new virtualZombie();
                send(new PACKET_SPAWN_ZOMBIE_GROWLER(this, ZombieSeats));
                _Zombie.ID = ZombieSeats;
                _Zombie.Health = 125;
                _Zombie.Points = 2;
                _Zombie.doDamage = 250;
                Zombies.Add(_Zombie);
                ZombieSeats++;
                spawnedGrowlers++;
                spawnedZombies++;
            }
            catch { }
        }

        public void spawnLover(int howMuch)
        {
            try
            {
                virtualZombie _Zombie = new virtualZombie();
                send(new PACKET_SPAWN_ZOMBIE_LOVER(this, ZombieSeats));
                _Zombie.ID = ZombieSeats;
                _Zombie.Health = 150;
                _Zombie.Points = 3;
                _Zombie.doDamage = 800;
                Zombies.Add(_Zombie);
                ZombieSeats++;
                spawnedLovers++;
                spawnedZombies++;
            }
            catch { }
        }

        public void spawnHandgeman(int howMuch)
        {
            try
            {
                virtualZombie _Zombie = new virtualZombie();
                send(new PACKET_SPAWN_ZOMBIE_HANDGEMAN(this, ZombieSeats));
                _Zombie.ID = ZombieSeats;
                _Zombie.Health = 233;
                _Zombie.Points = 4;
                _Zombie.doDamage = 1300;
                _Zombie.givesSkillPoints = true;
                Zombies.Add(_Zombie);
                ZombieSeats++;
                spawnedHandgemans++;
                spawnedZombies++;
            }
            catch { }
        }

        public void spawnChariot(int howMuch)
        {
            try
            {
                virtualZombie _Zombie = new virtualZombie();
                send(new PACKET_SPAWN_ZOMBIE_CHARIOT(this, ZombieSeats));
                _Zombie.ID = ZombieSeats;
                _Zombie.Health = 25000;
                _Zombie.Points = 50;
                _Zombie.doDamage = 2200;
                Zombies.Add(_Zombie);
                ZombieSeats++;
                spawnedChariots++;
                spawnedZombies++;
            }
            catch { }
        }

        public void spawnCrusher(int howMuch)
        {
            try
            {
                virtualZombie _Zombie = new virtualZombie();
                send(new PACKET_SPAWN_ZOMBIE_CRUSHER(this, ZombieSeats));
                _Zombie.ID = ZombieSeats;
                _Zombie.Health = 50000;
                _Zombie.Points = 100;
                _Zombie.doDamage = 2950;
                Zombies.Add(_Zombie);
                ZombieSeats++;
                spawnedCrushers++;
                spawnedZombies++;
            }
            catch { }
        }

        public bool isFinished = false;

        public void zombieStart()
        {
            zTime = (10);
            if (isFinished == true)
            {
                beginSpawn = true;
            }
        }

        public int zombieKills = 0;
        public int oldTime = 0;
        public int newTime = 0;

        public void loadZombieObjects()
        {
            for (int I = 0; I < Vehicles.Length; I++)
            {
                if (!(MapID == 50 && I == 1 || MapID == 48 && I == 5))
                {
                    Vehicles[I].Health = Vehicles[I].MaxHealth;
                    send(new PACKET_VEHICLE_RESPAWN(I));
                }
            }
        }

        public void newWave()
        {
            if (spawnedZombies <= zombieKills)
            {
                virtualZombie _Zombie = new virtualZombie();

                freezeZombies = true;
                send(new PACKET_ZOMBIE_WAVE(0));
                Wave += 1;
                send(new PACKET_ZOMBIE_WAVE(Wave));

                foreach (virtualZombie aZombie in Zombies)
                {
                    aZombie.Health = -1;
                    aZombie.ID = -1;
                }

                //Reset
                resetStats();

                //Do the new Wave
                xoldTime = RoundTimeSpent;
                prepareReady = true;

                /* Let Barrels Respawn */
                for (int I = 0; I < Vehicles.Length; I++)
                {
                    if (!(MapID == 50 && I == 1 || MapID == 48 && I == 5))
                    {
                        Vehicles[I].Health = Vehicles[I].MaxHealth;
                        send(new PACKET_VEHICLE_RESPAWN(I));
                    }
                }
            }
            else
            {
                return;
            }
        }

        public int xoldTime = 0;
        public bool prepareReady = false;
        public int calculateDifference = 0;

        public void prepareWave(int time)
        {
            try
            {
                if (spawnedZombies <= zombieKills)
                {
                    calculateDifference = xoldTime - time;
                    if (calculateDifference == -15000)
                    {
                        doWave(Wave);
                    }
                }
            }
            catch { }
        }

        public void doWave(int waveNumber)
        {
            resetStats();
            freezeZombies = false;
        }

        public void resetStats()
        {
            try
            {
                spawnedMadmans = 0;
                spawnedManiacs = 0;
                spawnedGrinders = 0;
                spawnedGrounders = 0;
                spawnedHeavys = 0;
                spawnedGrowlers = 0;
                spawnedLovers = 0;
                spawnedHandgemans = 0;
                spawnedChariots = 0;
                spawnedCrushers = 0;
                spawnedZombies = 0;
                toWave = 0;
                zombieKills = 0;
                Zombies.Clear();
                ZombieSeats = 4;
                prepareReady = false;
                waveTime = 15;
            }
            catch { }
        }

        public int spawnedZombies = 0;
        public bool freezeZombies = false;
        public bool firstWave = true;
        public int toWave = 20;
        public int zombiePoints = 0;
        public int zTime = 0;

        public int waveTime = 15;
        public bool waveReqFinished = false;

        public void waveSleep()
        {
            if (waveTime > 0)
            {
                waveReqFinished = false;
                waveTime--;
            }
            else
            {
                waveReqFinished = true;
            }
        }

        public void updateSleep()
        {
            if (zTime > 0)
            {
                isFinished = false;
                zTime--;
            }
            else
            {
                isFinished = true;
            }
        }

        public bool SeatsResetet = false;
        public int xKill = 0;

        public void resetSeats()
        {
            try
            {
                switch (Wave)
                {
                    case 0: { xKill = 21; } break; // Wave 1
                    case 1: { xKill = 21; } break; // Wave 2
                    case 2: { xKill = 21; } break; // Wave 3
                    case 4: { xKill = 21; } break; // Wave 5
                    case 5: { xKill = 21; } break; // Wave 6
                    case 6: { xKill = 21; } break; // Wave 7
                    case 7: { xKill = 21; } break; // Wave 8
                    case 8: { xKill = 21; } break; // Wave 9
                    case 9: { xKill = 21; } break; // Wave 10
                    case 10: { xKill = 21; } break; // Wave 11
                    case 11: { xKill = 21; } break; // Wave 12
                    case 15: { xKill = 21; } break; // Wave 16
                    case 16: { xKill = 21; } break; // Wave 17
                    case 20: { xKill = 21; } break; // Wave 21
                    case 21: { xKill = 21; } break; // Wave 22 (Final Wave)
                }
                if (ZombieSeats >= 25)
                {
                    freezeZombies = true;
                    if (zombieKills >= xKill)
                    {
                        ZombieSeats = 4;
                        SeatsResetet = true;
                        freezeZombies = false;
                    }
                }
                else
                {
                }
            }
            catch
            {
            }
        }

        public void SpawnZombies()
        {
            try
            {
                switch (Wave)
                {
                    case 0: { toWave = 30; } break; // Wave 1
                    case 1: { toWave = 30; } break; // Wave 2
                    case 2: { toWave = 30; } break; // Wave 3
                    case 3: { toWave = 22; } break; // Wave 4
                    case 4: { toWave = 28; } break; // Wave 5
                    case 5: { toWave = 23; } break; // Wave 6
                    case 6: { toWave = 19; } break; // Wave 7
                    case 7: { toWave = 25; } break; // Wave 8
                    case 8: { toWave = 18; } break; // Wave 9
                    case 9: { toWave = 24; } break; // Wave 10
                    case 10: { toWave = 30; } break; // Wave 11
                    case 11: { toWave = 32; } break; // Wave 12
                    case 12: { toWave = 17; } break; // Wave 13
                    case 13: { toWave = 24; } break; // Wave 14
                    case 14: { toWave = 11; } break; // Wave 15
                    case 15: { toWave = 24; } break; // Wave 16
                    case 16: { toWave = 25; } break; // Wave 17
                    case 17: { toWave = 25; } break; // Wave 18
                    case 18: { toWave = 11; } break; // Wave 19
                    case 19: { toWave = 10; } break; // Wave 20
                    case 20: { toWave = 24; } break; // Wave 21
                    case 21: { toWave = 20; } break; // Wave 22 (Final Wave)
                }
                if (freezeZombies) return;
                virtualZombie _Zombie = new virtualZombie();
                if (spawnedZombies >= toWave) { newWave(); return; }
                if (Wave > 22) endGame();

                switch (Wave)
                {
                    case 0: // Wave 1
                        if (!beginSpawn)
                        {
                            send(new PACKET_ZOMBIE_WAVE(0));
                            zombieStart();
                        }
                        else
                        {
                            if (firstWave)
                            {
                                if (isFinished && zTime == 0)
                                {
                                    firstWave = false;
                                }
                            }
                            else
                            {
                                if (spawnedMadmans < 31) spawnMadman(30);
                            }
                        }
                        break;
                    case 1: // Wave 2
                        if (spawnedMadmans < 11) spawnMadman(10);
                        if (spawnedManiacs < 21) spawnManiac(20);
                        break;
                    case 2: // Wave 3
                        if (spawnedMadmans < 11) spawnMadman(10);
                        if (spawnedManiacs < 11) spawnManiac(10);
                        if (spawnedGrounders < 11) spawnGrounder(10);
                        break;
                    case 3: // Wave 4
                        if (spawnedManiacs < 6) spawnManiac(5);
                        if (spawnedMadmans < 6) spawnMadman(5);
                        if (spawnedGrowlers < 6) spawnGrowler(5);
                        if (spawnedHeavys < 8) spawnHeavy(7);
                        break;
                    case 4: // Wave 5
                        if (spawnedGrinders < 11) spawnGrinder(10);
                        if (spawnedHeavys < 11) spawnHeavy(10);
                        if (spawnedMadmans < 9) spawnMadman(8);
                        break;
                    case 5: // Wave 6
                        if (spawnedGrowlers < 8) spawnGrowler(8);
                        if (spawnedMadmans < 11) spawnMadman(10);
                        if (spawnedHeavys < 6) spawnHeavy(5);
                        break;
                    case 6: // Wave 7
                        if (spawnedGrounders < 10) spawnGrounder(9);
                        if (spawnedGrinders < 10) spawnGrinder(9);
                        if (spawnedChariots < 2) spawnChariot(1);
                        break;
                    case 7: // Wave 8
                        if (spawnedGrounders < 16) spawnGrounder(15);
                        if (spawnedManiacs < 6) spawnManiac(5);
                        if (spawnedGrowlers < 6) spawnGrowler(5);
                        break;
                    case 8: // Wave 9
                        if (spawnedHeavys < 4) spawnHeavy(3);
                        if (spawnedGrounders < 8) spawnGrounder(7);
                        if (spawnedGrowlers < 4) spawnGrowler(3);
                        if (spawnedGrinders < 6) spawnGrinder(5);
                        break;
                    case 9: // Wave 10
                        if (spawnedChariots < 4) spawnChariot(3);
                        if (spawnedHeavys < 4) spawnHeavy(3);
                        if (spawnedGrounders < 11) spawnGrounder(10);
                        if (spawnedGrinders < 9) spawnGrinder(8);
                        break;
                    case 10: // Wave 11
                        if (spawnedMadmans < 5) spawnMadman(4);
                        if (spawnedGrinders < 5) spawnGrinder(4);
                        if (spawnedGrowlers < 5) spawnGrowler(4);
                        if (spawnedHeavys < 11) spawnHeavy(10);
                        if (spawnedManiacs < 5) spawnManiac(4);
                        if (spawnedGrounders < 5) spawnGrounder(4);
                        break;
                    case 11: // Wave 12
                        if (spawnedGrinders < 9) spawnGrinder(8);
                        if (spawnedGrowlers < 11) spawnGrowler(10);
                        if (spawnedHeavys < 15) spawnHeavy(14);
                        break;
                    case 12: // Wave 13
                        if (spawnedHeavys < 16) spawnHeavy(15);
                        if (spawnedChariots < 3) spawnChariot(2);
                        break;
                    case 13: // Wave 14
                        if (spawnedGrowlers < 11) spawnGrowler(10);
                        if (spawnedGrounders < 10) spawnGrounder(9);
                        if (spawnedHeavys < 6) spawnHeavy(5);
                        break;
                    case 14: // Wave 15
                        if (spawnedCrushers < 2) spawnCrusher(1);
                        if (spawnedChariots < 3) spawnChariot(2);
                        if (spawnedHeavys < 9) spawnHeavy(8);
                        break;
                    case 15: // Wave 16
                        if (spawnedGrinders < 11) spawnGrinder(10);
                        if (spawnedGrowlers < 11) spawnGrowler(10);
                        if (spawnedGrounders < 5) spawnGrounder(4);
                        break;
                    case 16: // Wave 17
                        if (spawnedMadmans < 6) spawnMadman(5);
                        if (spawnedHeavys < 11) spawnHeavy(10);
                        if (spawnedGrounders < 11) spawnGrounder(10);
                        break;
                    case 17: // Wave 18
                        if (spawnedGrounders < 7) spawnGrounder(6);
                        if (spawnedGrowlers < 6) spawnGrowler(5);
                        if (spawnedChariots < 3) spawnChariot(2);
                        if (spawnedMadmans < 11) spawnMadman(10);
                        break;
                    case 18: // Wave 19
                        if (spawnedGrounders < 6) spawnGrounder(5);
                        if (spawnedGrowlers < 6) spawnGrowler(5);
                        if (spawnedCrushers < 2) spawnCrusher(1);
                        break;
                    case 19: // Wave 20
                        if (spawnedGrounders < 4) spawnGrounder(3);
                        if (spawnedManiacs < 4) spawnManiac(3);
                        if (spawnedGrowlers < 4) spawnGrowler(3);
                        if (spawnedChariots < 2) spawnChariot(1);
                        break;
                    case 20: // Wave 21
                        if (spawnedMadmans < 11) spawnMadman(10);
                        if (spawnedGrinders < 10) spawnGrinder(9);
                        if (spawnedGrounders < 6) spawnGrounder(5);
                        break;
                    case 21: // Wave 22 (Final Wave)
                        if (spawnedChariots < 6) spawnChariot(5);
                        if (spawnedCrushers < 6) spawnCrusher(5);
                        if (spawnedGrounders < 6) spawnGrounder(5);
                        if (spawnedGrinders < 6) spawnGrinder(5);
                        break;
                }
            }
            catch { }
        }

        #endregion

        public int AliveUsers(int Side)
        {
            int Count = 0;
            foreach (virtualUser RoomUser in Players)
                if (RoomUser.Health > 5 && getSide(RoomUser) == Side) Count++;
            return Count;
        }

        public int switchSide(virtualUser User)
        {
            if (RoomStatus != 1) return -1;
            if (User != null && User.Room != null && User.Room.ID == this.ID)
            {
                int oldSlot = User.RoomSlot;
                int Side = getSide(User);

                if (Side == 0)
                {
                    for (int I = MaxPlayers / 2; I < MaxPlayers; I++)
                    {
                        if (Users.ContainsKey(I) == false)
                        {
                            if (User.RoomSlot == RoomMasterSlot)
                                RoomMaster = I;

                            Users.Remove(oldSlot);
                            Users.Add(I, User);

                            User.RoomSlot = I;
                            return I;
                        }
                    }
                }
                else
                {
                    for (int I = 0; I < MaxPlayers / 2; I++)
                    {
                        if (Users.ContainsKey(I) == false)
                        {
                            if (User.RoomSlot == RoomMasterSlot)
                                RoomMaster = I;

                            Users.Remove(oldSlot);
                            Users.Add(I, User);

                            User.RoomSlot = I;
                            return I;
                        }
                    }
                }
            }
            return -1;
        }

        public void CheckTimeEnd()
        {
            try
            {
                if (cDerbRounds + 1 >= explosiveRounds || cNiuRounds + 1 >= explosiveRounds)
                {
                    endGame();
                }
                else if (bombPlanted == true)
                {
                    newRound(0); cDerbRounds++;
                }
                else if (bombPlanted == false)
                {
                    newRound(1); cNiuRounds++;
                }

                RoundTimeLeft = 180000;
                RoundTimeSpent = 0;
            }
            catch
            {
            }
        }

        public void update()
        {
            try
            {
                if (Users.Count > 0)
                {
                    if (GameActive)
                    {
                        if (LastTick != DateTime.Now.Second && !EndGameFreeze)
                        {
                            LastTick = DateTime.Now.Second;

                            if (SpawnLocation > 15) SpawnLocation = 0;

                            foreach (Virtual_Objects.User.virtualUser RoomUser in Players)
                            {
                                if (RoomUser.SpawnProtection > 0)
                                {
                                    RoomUser.SpawnProtection--;
                                }
                            }

                            if (RoomStatus == 2 && (Mode != 1 && Channel == 1))
                            {
                                if (getSideCount(0) == 0 || getSideCount(1) == 0)
                                    endGame();
                            }

                            if (Channel != 4)
                            {
                                VehicleRespawnCount++;
                                if (VehicleRespawnCount == 120)
                                {
                                    for (int I = 0; I < Vehicles.Length; I++)
                                    {
                                        if (Vehicles[I].Health <= 0)
                                        {
                                            Vehicles[I].Health = Vehicles[I].MaxHealth;
                                            send(new PACKET_VEHICLE_RESPAWN(I));
                                        }
                                    }
                                    VehicleRespawnCount = 0;
                                }
                            }

                            #region KickUser
                            if (VoteKickTime > 0)
                            {
                                VoteKickTime--;
                            }
                            if (VoteKickTime == 0 || KickYes > KickNo + 1)
                            {

                                if (KickSeat != -1)
                                {
                                    if (KickYes > KickNo)
                                    {
                                        virtualUser nUser = this.getPlayer(KickSeat);
                                        int newMaster = RoomMasterSlot;

                                        if (nUser != null && nUser.SessionID > 0)
                                        {
                                            foreach (virtualUser _Client in Players)
                                            {
                                                _Client.send(new PACKET_CHAT("SYSTEM", PACKET_CHAT.ChatType.Room_ToTeam, "SYSTEM >> User " + nUser.Nickname + " was kicked from the room from team " + (getSide(_Client) == 0 ? "Derbaran" : "NIU"), 999, _Client.Nickname));
                                                _Client.send(new PACKET_ROOM_KICK(KickSeat));
                                                _Client.send(new PACKET_LEAVE_ROOM(nUser, this, KickSeat, newMaster));
                                            }

                                        }
                                        else
                                        {
                                            foreach (virtualUser _Client in Players)
                                            {
                                                _Client.send(new PACKET_ROOM_DATA(_Client, KickString));
                                            }
                                        }
                                    }
                                    else
                                    {
                                        foreach (virtualUser _Client in Players)
                                        {
                                            _Client.send(new PACKET_ROOM_DATA(_Client, KickString));
                                        }
                                    }

                                    KickAlready = false;
                                    KickYes = 0;
                                    KickNo = 0;
                                    KickSeat = -1;
                                    VoteKickTime = 0;
                                }
                            }
                            #endregion

                            // Temp Fix
                            int activeUsers = 0;
                            for (int i = 0; i < Users.Count; i++)
                            {
                                Virtual_Objects.User.virtualUser u = (Virtual_Objects.User.virtualUser)Users[i];
                                if (u != null)
                                {
                                    activeUsers++;
                                }
                            }

                            if (activeUsers <= 0)
                            {
                                RoomManager.removeRoom(this.Channel, this.ID);
                                return;
                            }

                            if (RoundTimeLeft > 0) RoundTimeLeft -= 1000;

                            RoundTimeSpent += 1000;

                            //if ((Mode == 0 && RoundTimeSpent > 10000)) { RoundTimeSpent = 0; }

                            switch (Mode)
                            {
                                case 0: // Explosive
                                    {
                                        if (cNiuRounds >= explosiveRounds || cDerbRounds >= explosiveRounds) { endGame(); }
                                        if (Users.Count > 1)
                                        {
                                            if (AliveUsers(0) == 0 && AliveUsers(1) > 0 && bombPlanted == false)
                                            {
                                                newRound(1); cNiuRounds++;
                                            }
                                            else if (AliveUsers(1) == 0 && AliveUsers(0) > 0)
                                            {
                                                newRound(0); cDerbRounds++;
                                            }
                                            else if (AliveUsers(1) == 0 && AliveUsers(0) == 0)
                                            {
                                                if (bombPlanted == true)
                                                {
                                                    newRound(0); cDerbRounds++;
                                                }
                                                else
                                                {
                                                    newRound(1); cNiuRounds++;
                                                }
                                            }
                                        }
                                        if (RoundTimeLeft <= 0) { CheckTimeEnd(); }
                                        break;
                                    }
                                case 1: // FFA
                                    {
                                        if (SpawnLocation < 0 || SpawnLocation >= 19) SpawnLocation = 0;

                                        foreach (virtualUser RoomUser in Players)
                                        {
                                            if (RoomUser.rKills >= highestKills)
                                                highestKills = RoomUser.rKills;
                                        }

                                        if (RoundTimeLeft <= 0 || highestKills >= (10 + (5 * Rounds)))
                                        {
                                            endGame(); return;
                                        }
                                        break;
                                    }
                                case 2: // Team Death Match
                                    {
                                        if (RoundTimeLeft <= 0 || KillsNIULeft == 0 || KillsDeberanLeft == 0) { endGame(); return; }
                                        break;
                                    }
                                case 7: // Zombie Mode
                                    {
                                        if (prepareReady) prepareWave(RoundTimeSpent);
                                        if (toWave >= 25) resetSeats();
                                        updateSleep();
                                        if (Wave > 22) endGame();
                                        if (readyZombie)
                                        {
                                            SpawnZombies();
                                        }
                                        if (AliveUsers(0) == 0)
                                            endGame();
                                        break;
                                    }
                                case 8: // Zombie Mode
                                    {
                                        if (prepareReady) prepareWave(RoundTimeSpent);
                                        if (toWave >= 25) resetSeats();
                                        updateSleep();
                                        if (Wave > 22) endGame();
                                        if (readyZombie)
                                        {
                                            SpawnZombies();
                                        }
                                        if (AliveUsers(0) == 0)
                                            endGame();
                                        break;
                                    }
                            }

                            if (Sleep) return;
                            send(new PACKET_ROOM_SPAWN_TICK(this));
                        }
                    }
                }
                else
                {
                    RoomManager.removeRoom(Channel, ID);
                }
            }
            catch (Exception ex)
            {
                //Log.WriteError("Error at Update @ Room: " + ex.Message);
            }
        }

        public int cNiuRounds, cDerbRounds;

        public struct Planting
        {
            public int id;
            public virtualUser _v;
            public string _code;
            public bool _used;
        }
        public ArrayList Plantings = new ArrayList();
        public int AddPlacement(virtualUser v, string ItemCode)
        {
            int ReturnID = Plantings.Count;
            Planting p = new Planting();
            p._v = v;
            p._code = ItemCode;
            p._used = false;
            Plantings.Add(p);
            ReturnID = Plantings.Count;
            p.id = ReturnID;
            return ReturnID;
        }

        public Planting getPlant(int iID)
        {
            foreach (Planting p in Plantings)
            {
                if (p.id == iID)
                {
                    return p;
                }
            }

            return new Planting();
        }

        public void ResetRoomStats(virtualUser Player)
        {
            try
            {
                Player.rKills = Player.rDeaths = Player.rFlags = Player.rPoints = Player.droppedAmmo = Player.droppedFlash = Player.droppedM14 = 0; // Reset Room Kills & Deaths
                Player.DinarEarned = Player.ExpEarned = Player.EarnedPoints = 0;
                Player.Health = 1000;
                Player.isReady = false;
                Player.isSpawned = false;
            }
            catch { }
        }

        public string getClanName(int Side)
        {
            foreach (virtualUser RoomUser in Players)
            {
                if (getSide(RoomUser) == Side)
                {
                    return RoomUser.ClanName;
                }
            }
            return "None";
        }

        public void endGame()
        {
            try
            {
                if (EndGameFreeze) return;
                EndGameFreeze = true;
                System.Threading.Thread.Sleep(1000);
                GameActive = false;
                bombPlanted = false;
                bombDefused = false;
                RoundTimeSpent = 10000;

                int SideWon = -1;
                int SideLose = -1;

                foreach (Virtual_Objects.User.virtualUser Player in Players)
                {
                    int ExplosiveTeamPoints = (getSide(Player) == 0) ? cDerbExplosivePoints : cNIUExplosivePoints;
                    int haveUP1 = 0;
                    int haveUP2 = 0;
                    int haveDinar = 0;
                    /* PX's Buff*/
                    if (Player.hasItem("CD01") && Player.hasItem("CD02")) haveUP1 = 3;
                    else if (Player.hasItem("CD01")) haveUP1 = 2;
                    else if (Player.hasItem("CD02")) haveUP1 = 1;

                    if (Player.hasItem("CC05")) haveUP2 = 1;

                    if (Player.hasItem("CE01") && Player.hasItem("CE02")) haveDinar = 3;
                    else if (Player.hasItem("CE02")) haveDinar = 2;
                    else if (Player.hasItem("CE01")) haveDinar = 1;

                    double DinarRate = (SuperMaster) ? 1.10 : 1;
                    double ExpRate = (SuperMaster) ? 1.05 : 1.0;
                    double[] PremiumBonus = new double[] { 0, 0.20, 0.30, 0.50, 0.90 };
                    double[] ExpUP = new double[] { 0, 0.20, 0.30, 0.50 };
                    double[] DinUP = new double[] { 0, 0.20, 0.30, 0.50 };
                    double[] DoubleUP = new double[] { 0, 0.25 };
                    ExpRate += PremiumBonus[Player.Premium];
                    ExpRate += ExpUP[haveUP1];
                    ExpRate += DoubleUP[haveUP2];
                    DinarRate += DoubleUP[haveUP2];
                    DinarRate += DinUP[haveDinar];

                    Player.EarnedPoints = Player.rPoints * 2 + Player.rKills + ExplosiveTeamPoints;

                    int _ExpEarned = 0;
                    int _DinarEarned = 0;
                    int isAI = (Channel == 4 ? 1 : 3);
                    double ServerExpRate = 1.8;
                    _ExpEarned = Convert.ToInt32(Math.Ceiling(((double)Player.EarnedPoints * isAI * ExpRate) * ServerExpRate));
					_DinarEarned = Convert.ToInt32(Math.Ceiling((((double)Player.EarnedPoints * isAI * DinarRate) * ServerExpRate )* Config.Rates));

                    if (Channel != 4) // If isn't Zombie channel
                    {
                        if (Mode == 0 && Channel == 1)
                        {
                            _DinarEarned *= 2;
                            _ExpEarned *= 2;
                        }

                        if (Player.PCItem)
                            _ExpEarned *= 3;

                        if (Program.isEvent == true)
                        {
                            _ExpEarned *= Program.EXPEvent;
                            _DinarEarned *= Program.DinarEvent;
                        }
                    }

                    int CurrentLevel = LevelCalculator.getLevelforExp(Player.Exp);

                    Player.Exp += _ExpEarned; // Add exp

                    if (RoomType == 3) // If it's event room
                    {
                        _DinarEarned += 5000;
                    }
                    else if (RoomType == 1) // If it's clanwar
                    {
                        int DerbScore = (Mode == 0 ? cDerbExplosivePoints : KillsDeberanLeft);
                        int NIUScore = (Mode == 0 ? cNiuRounds + 1 : KillsNIULeft);
                        string DerbTeam = getClanName(0);
                        string NIUTeam = getClanName(1);
                        if (DerbScore > NIUScore)
                        {
                            SideWon = 0;
                            SideLose = 1;
                        }
                        else if (NIUScore > DerbScore)
                        {
                            SideWon = 1;
                            SideLose = 0;
                        }
                        UserManager.sendToServer(new PACKET_CHAT("Server", PACKET_CHAT.ChatType.Notice1, "NOTICE: ClanWar end! " + DerbTeam + " vs. " + NIUTeam, 100, "NULL"));
                    }

                    if (Player.Exp >= LevelCalculator.getExpForLevel(CurrentLevel + 1)) // If ranked up
                    {
                        Player.send(new PACKET_LEVEL_UP(Player));
                        Player.Dinar += 25000;
                        Player.Cash += 250;
                        Log.WriteLine("---" + Player.Nickname + " has level upped to " + LevelCalculator.getLevelforExp(Player.Exp) + "---");
                        DB.runQuery("UPDATE users SET cash='" + Player.Cash + "' WHERE id='" + Player.UserID + "'");
                    }
                    Player.Dinar += _DinarEarned; // Add dinar
                    Player.ExpEarned = _ExpEarned;
                    Player.DinarEarned = _DinarEarned;
                    if (Channel != 4)
                    {
                        Player.Kills += Player.rKills;
                        Player.Deaths += Player.rDeaths;
                    }
                    DB.runQuery("UPDATE users SET kills='" + Player.Kills + "',deaths='" + Player.Deaths + "', exp='" + Player.Exp + "', dinar='" + Player.Dinar + "',cash='" + Player.Cash + "' WHERE id=" + Player.UserID);
                }
                if (SideWon != -1 && SideLose != -1)
                {
                    int WonClanID = getClanID(SideWon);
                    int LoseClanId = getClanID(SideLose);
                    ClanManager.getClan(WonClanID).clanWarWin++;
                    ClanManager.getClan(LoseClanId).clanWarLose++;
                    DB.runQuery("UPDATE clans SET win=win+1 WHERE id='" + WonClanID + "'");
                    DB.runQuery("UPDATE clans Set lose=lose+1 WHERE id='" + LoseClanId + "'");
                }

                if (Channel == 4)
                    send(new PACKET_END_GAME_AI(this));
                else
                    send(new PACKET_END_GAME(this));

                foreach (Virtual_Objects.User.virtualUser Player in Players)
                {
                    ResetRoomStats(Player);
                    if (RoomType == 3)
                    {
                        Player.send(new PACKET_CHAT("SYSTEM", PACKET_CHAT.ChatType.Room_ToAll, "SISTEMA >> Tienes 5.000 Dinars para jugar un evento!", 999, "NULL"));
                    }
                    Player.send(new SP_ROOM_INFO(51, RoomMasterSlot, 55, 2, 1, 0, MapID, 0, 0, 0, 0, 0, 0, 0));
                }
                highestKills = cNiuRounds = cDerbRounds = KillsNIULeft = KillsDeberanLeft = 0;

                RoomStatus = 1;
            }
            catch { }
        }

        public void remove()
        {
            if (Players.Count > 0)
            {
                if (RoomStatus != 1)
                {
                    endGame();
                }

                foreach (virtualUser Player in Players)
                {
                    Player.send(new PACKET_ROOM_KICK(Player.RoomSlot));
                }
            }
            RoomManager.removeRoom(Channel, ID);
        }

        public int getSide(virtualUser Client)
        {
            if (Client.isSpectating) return -1;
            if (Channel == 4) return 0;
            if (Client.RoomSlot < (MaxPlayers / 2))
                return 0;
            else
                return 1;
        }

        public int getSideCount(int Side)
        {
            int Count = 0;
            foreach (virtualUser RoomUser in Players)
            {
                if (getSide(RoomUser) == Side)
                    Count++;
            }
            return Count;
        }

        public int getIDOfPlayer(virtualUser User)
        {
            for (int i = 0; i < MaxPlayers; i++)
            {
                if ((oPlayers.GetValue(i) is virtualUser) && oPlayers.GetValue(i).Equals(User))
                {
                    return i;
                }
            }

            return -1;
        }

        public bool isMyClan(virtualUser User)
        {
            foreach (virtualUser RoomUser in Players)
            {
                if (User.ClanID == RoomUser.ClanID)
                    return true;
            }
            return false;
        }

        public int getClanSide(virtualUser User)
        {
            foreach (virtualUser RoomUser in Players)
            {
                if (RoomUser.ClanID == User.ClanID)
                {
                    return getSide(RoomUser);
                }
            }
            if (getSideCount(0) == 0) return 0;
            else if (getSideCount(1) == 0) return 1;
            return -1;
        }

        public int getClanID(int Side)
        {
            int ID = -1;
            foreach (virtualUser Clients in Players)
            {
                if (getSide(Clients) == Side)
                    ID = Clients.ClanID;
            }
            return ID;
        }

        public bool joinClanWar(virtualUser User)
        {
            User.isReady = false;
            User.rKills = User.rDeaths = User.rPoints = User.Health = 0;
            int ClanSide = getClanSide(User);

            if (ClanSide == -1) return false;

            if (getSideCount(ClanSide) > (MaxPlayers / 2)) return false;

            if (Users.Count <= 0)
            {
                User.isInRoom = true;
                User.Room = this;
                User.RoomSlot = 0;
                Users.Add(0, User);
                RoomMaster = 0;
                return true;
            }
            else
            {
                if (Users.Count < MaxUsers)
                {
                    User.isInRoom = true;
                    int Incr = 0;
                    for (int I = 0; I < MaxUsers; I++)
                    {
                        if (ClanSide == 0)
                        {
                            if (Users.ContainsKey(I / 2) == false)
                            {
                                User.RoomSlot = I / 2;
                                User.Room = this;
                                Users.Add(I / 2, User);
                                User.send(new PACKET_JOIN_ROOM(User, this));
                                DeberanPlayers.Add(User);
                                //Name = getClanName(0) + " vs. " + getClanName(1);
                                return true;
                            }
                        }
                        else
                        {
                            if (Users.ContainsKey((MaxUsers / 2) + Incr) == false)
                            {
                                User.RoomSlot = (MaxUsers / 2) + Incr;
                                User.Room = this;
                                Users.Add((MaxUsers / 2) + Incr, User);
                                User.send(new PACKET_JOIN_ROOM(User, this));
                                NIUPlayers.Add(User);
                                //Name = getClanName(0) + " vs. " + getClanName(1);
                                return true;
                            }
                            Incr++;
                        }
                    }
                }
            }
            return false;
        }

        public bool joinUser(virtualUser User)
        {
            User.isReady = false;
            User.isSpawned = false;
            User.rKills = User.rDeaths = User.rPoints = User.Health = 0;

            if (RoomType == 1)
            {
                if (joinClanWar(User) == true)
                {
                    return true;
                }
                else
                    return false;
            }

            if (Users.Count <= 0)
            {
                User.Room = this;
                User.RoomSlot = 0;
                Users.Add(0, User);
                RoomMaster = 0;
                return true;
            }
            else
            {
                if (User.Channel != 4)
                {
                    if (Users.Count < MaxUsers)
                    {
                        User.isInRoom = true;
                        int Incr = 0;
                        for (int I = 0; I < MaxUsers; I++)
                        {
                            if (I % 2 == 0)
                            {
                                if (Users.ContainsKey(I / 2) == false)
                                {
                                    User.RoomSlot = I / 2;
                                    User.Room = this;
                                    Users.Add(I / 2, User);
                                    User.send(new PACKET_JOIN_ROOM(User, this));
                                    DeberanPlayers.Add(User);
                                    return true;
                                }
                            }
                            else
                            {
                                if (Users.ContainsKey((MaxUsers / 2) + Incr) == false)
                                {
                                    User.RoomSlot = (MaxUsers / 2) + Incr;
                                    User.Room = this;
                                    Users.Add((MaxUsers / 2) + Incr, User);
                                    User.send(new PACKET_JOIN_ROOM(User, this));
                                    NIUPlayers.Add(User);
                                    return true;
                                }
                                Incr++;
                            }
                        }
                    }
                }
                else
                {
                    for (int I = 0; I < 4; I++)
                    {
                        if (Users.ContainsKey(I) == false)
                        {
                            User.RoomSlot = I;
                            User.Room = this;
                            Users.Add(I, User);
                            User.send(new PACKET_JOIN_ROOM(User, this));
                            DeberanPlayers.Add(User);
                            break;
                        }
                    }
                    return true;
                }
            }
            return false;
        }

        public virtualUser getPlayer(int SlotID)
        {
            if (Users.ContainsKey(SlotID))
            {
                return (virtualUser)Users[SlotID];
            }
            return null;
        }

        public bool removeUser(int SlotID)
        {
            try
            {
                if (SlotID >= 0 && Users.ContainsKey(SlotID))
                {
                    virtualUser uObj = (virtualUser)Users[SlotID];
                    if (uObj.currentVehicle != null)
                    {
                        //TODO: Remove user from the car (202 subtype of the room data)
                    }
                    uObj.isInRoom = false;
                    if (Channel != 4)
                    {
                        uObj.Kills += uObj.rKills;
                        uObj.Deaths += uObj.rDeaths;
                    }
                    uObj.Room = null;
                    uObj.RoomSlot = -1;
                    Users.Remove(SlotID);

                    if (Mode == 1 && Channel == 1) // Check if it's FFA
                    {
                        foreach (virtualUser User in Players)
                        {
                            if (User.rKills >= highestKills)
                                highestKills = User.rKills; // Set highest FFA kill
                        }
                    }
                    //else if (RoomType == 1)
                    //Name = getClanName(0) + " vs. " + getClanName(1);

                    if (SlotID == RoomMaster && Users.Count > 0) /* Select New Master First */
                    {
                        SuperMaster = false; // Remove Exp Buff
                        for (int I = 0; I < MaxPlayers; I++)
                        {
                            if (Users.ContainsKey(I))
                            {
                                RoomMaster = I;
                                break;
                            }
                        }
                    }

                    send(new PACKET_LEAVE_ROOM(uObj, this, SlotID, RoomMaster)); // Send to the room about the user left

                    uObj.send(new PACKET_LEAVE_ROOM(uObj, this, SlotID, RoomMaster));

                    if (RoomStatus != 1 && Users.Count <= 1 && Channel != 4)
                    {
                        endGame(); // End Game
                    }
                    else if (Users.Count <= 0) // Remove room if it's empty
                    {
                        RoomManager.removeRoom(this.Channel, this.ID);
                    }

                    // Update the lobby
                    UserManager.refreshRoom(this);
                    return true;
                }

                return false;
            }
            catch { return false; }
        }
    }
}